<?php defined('SYSPATH') or die('No direct script access.');
/*
 * @author Anton Pomeschenko <progik.ru>
 * @package Akismet
 * @licence new BSD
 
 * Usage example;
 *
	$akismet = new Akismet;
	$akismet->author = $post->name;
	$akismet->email = $post->email;
	$akismet->url = $post->site;
	$akismet->content = $post->comment;
	$akismet->type = 'comment';
	
	if ($akismet->check_spam())
	{
		echo "this is spam";die;
	}
	
	
	or
	
	$post = new Validation($_POST)->add_callbacks('comment', 'Akismet::verify');
*/

class Akismet_Core {
	
	/*
	 * This fields are ignored when send array $_SERVER 
	*/
	protected static $ignore = array(
			'HTTP_COOKIE',
			'HTTP_X_FORWARDED_FOR',
			'HTTP_X_FORWARDED_HOST',
			'HTTP_MAX_FORWARDS',
			'HTTP_X_FORWARDED_SERVER',
			'REDIRECT_STATUS',
			'SERVER_PORT',
			'PATH',
			'DOCUMENT_ROOT',
			'SERVER_ADMIN',
			'QUERY_STRING',
			'PHP_SELF',
			'argv'
		);
	
	protected $params = array();
	
	protected $errors = array();
	/*
	 * Config params
	*/
	protected $config = array();
	
	public function __construct ($group = 'default')
	{
		$this->params = Kohana::config('akismet.'.$group);
		
		if ($this->params['auto_check_api_key'] AND !$this->verify_key())
			throw new Kohana_Database_Exception('akismet.invalid_api_key', $this->params['api_key']);
	}
	
	/*
	 * Set params. Allowed: author, email, url, content, type
	*/
	public function __set($key, $value)
	{
		$attributes = array('author', 'email', 'url','content', 'type');
		
		if (in_array($key, $attributes))
			$this->config[$key] = $value;

		return $this;
	}
	
	/*
	 * Send request to server and get response
	 * @param string request   Akismet request
	 * @param string string    type of request. for example: verify-key, comment-check, submit-spam, submit-ham
	 * @return string return response
	 * @access protected
	*/
	protected function send_request ($request, $type)
	{
		$version = $this->params['version'];
		$server = $this->params['server'];
		$port = $this->params['port'];
		$api_key = $this->params['api_key'];
		
		if ($type != 'verify-key')
			$server = $api_key.'.'.$server;
		
		$http_request  = "POST /$version/$type HTTP/1.0\r\n";
		$http_request .= "Host: $server\r\n";
		$http_request .= "Content-Type: application/x-www-form-urlencoded; charset=utf-8\r\n";
		$http_request .= "Content-Length: " . strlen($request) . "\r\n";
		$http_request .= "User-Agent: Kohana akismet library\r\n";
		$http_request .= "\r\n";
		$http_request .= $request;

		$response = '';
		if( false !== ( $fs = @fsockopen($server, $port, $errno, $errstr, 3) ) ) {
			fwrite($fs, $http_request);
			while ( !feof($fs) )
				$response .= fgets($fs, 1160); // One TCP-IP packet
			fclose($fs);
			$response = explode("\r\n\r\n", $response, 2);
		} else
			$this->errors[] = 'AKISMET_SERVER_NOT_FOUND';
		
		return $response;
	}
	
	/*
	 * make request
	 * @return string     form and return string with params of request
	*/
	protected function make_request ()
	{
		$data = array(
			'blog'					=>	url::site(),
			'user_ip'				=>	Input::instance()->ip_address(),
			'user_agent'			=>	Kohana::$user_agent,
			'referrer'				=>	request::referrer(),
			'permalink'				=>	'',
			'comment_type'			=>	$this->config['type'],
			'comment_author'		=>	$this->config['author'],
			'comment_author_email'	=>	$this->config['email'],
			'comment_author_url'	=>	$this->config['url'],
			'comment_content'		=>	$this->config['content']
		);
		
		foreach ($_SERVER as $key=>$value)
		{
			if (!in_array($key, self::$ignore))
				$data[$key] = $value;
		}
		
		$query = '';
		
		foreach($data as $key=>$value)
			$query .= $key . '=' . urlencode(stripslashes($value)) . '&';
		
		return $query;
	}

	/*
	 * Function verify key
	 * @return bool 
	*/
	public function verify_key() {
		$api_key = Kohana::config('akismet.api_key');
		$blog = urlencode(url::site());
		
		$response = $this->send_request("key=$api_key&blog=$blog", 'verify-key');
		
		return ('valid' == $response[1]);
	}

	/*
	 * Check spam.
	 * @return bool 
	*/
	public function check_spam ()
	{
		// clear errors
		$this->errors = array();
		// get response
		$response = $this->send_request($this->make_request(), 'comment-check');
		return ($response == "true");
	}
	
	/*
	 * Submit spam
	 * @return none
	*/
	public function submit_spam ()
	{
		// clear errors
		$this->errors = array();
		// get response
		$this->send_request($this->make_request(), 'submit-spam');
	}
	
	/*
	 * Submit ham
	 * @return none
	*/
	public function submit_ham ()
	{
		// clear errors
		$this->errors = array();
		// get response
		$this->send_request($this->make_request(), 'submit-ham');
	}
	
	/*
	 * Get array of errors
	 * @return errors
	*/
	public function get_errors()
	{
		return $this->errors;
	}
	
	/*
	 * Verify comment is spam?
	 * usefull for validation callbacks
	 * Example:
	 * $post = new Validation($_POST)->add_callbacks('comment', 'Akismet::verify');
	*/
	public static function verify(Validation $post, $field)
	{
		$akismet = new Akismet;
		$akismet->author = $post->name;
		$akismet->email = $post->email;
		$akismet->url = $post->site;
		$akismet->content = $post->comment;
		$akismet->type = 'comment';
		
		if ($akismet->check_spam() OR $akismet->get_errors())
		{
			$post->add_error($field, 'is_spam');
			Kohana::log ('akismet.spam_detected', 'info');
		}
	}
} // End Akismet